package com.projectbox.web;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;

import com.projectbox.model.Folder;
import com.projectbox.model.Resource;
import com.projectbox.model.User;
import com.projectbox.model.Project;
import com.projectbox.service.ProjectService;
import com.projectbox.service.ResourceService;
import com.projectbox.service.UserService;

@Controller
@RequestMapping("/myproject")
public class MyProjectController extends MultiActionController {

	private Logger logger = LoggerFactory.getLogger(getClass());

	private UserService userService;
	private ProjectService projectService;
	private ResourceService resourceService;

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	public void setProjectService(ProjectService projectService) {
		this.projectService = projectService;
	}

	public void setResourceService(ResourceService resourceService) {
		this.resourceService = resourceService;
	}

	@RequestMapping(method = RequestMethod.GET)
	public String displayMyProjects(Model model) {
		User user = userService.getCurrentUser();
		List<Project> projectList = this.projectService
				.findManagedProjects(user);

		model.addAttribute("projectList", projectList);
		model.addAttribute("user", user);

		return "myproject";
	}

	@RequestMapping(value = "/{pid}", method = RequestMethod.GET)
	public String displayProjectContributors(@PathVariable Long pid, Model model) {
		logger.debug("view contributors project with id " + pid);

		User currentUser = this.userService.getCurrentUser();
		Project project = this.projectService.findProject(pid);
		
		if (project != null) {
			if (project.getMid() != currentUser.getId()) {
				return "redirect:/error/403.jsp";
			}
		} else {
			return "redirect:/error/400.jsp";
		}
		
		model.addAttribute("contributorType", "Approve Contributors");
		model.addAttribute("user", currentUser);
		model.addAttribute("project", project);
		model.addAttribute("contributors",
				projectService.findProjectContributor(pid));

		return "projectcontributor";
	}
	
	@RequestMapping(value = "/{pid}/pending", method = RequestMethod.GET)
	public String displayPendingContributors(@PathVariable Long pid, Model model) {
		logger.debug("view pending contributors project with id " + pid);

		User currentUser = this.userService.getCurrentUser();
		Project project = this.projectService.findProject(pid);
		
		if (project != null) {
			if (project.getMid() != currentUser.getId()) {
				return "redirect:/error/403.jsp";
			}
		} else {
			return "redirect:/error/400.jsp";
		}
		
		model.addAttribute("contributorType", "Pending Contributors");
		model.addAttribute("user", currentUser);
		model.addAttribute("project", project);
		model.addAttribute("contributors",
				projectService.findProjectPendingUser(pid));

		return "projectcontributor";
	}
	
	/**
	 * Accept private project contribute request
	 * 
	 * @param pid
	 * @return
	 */
	@RequestMapping(value = "/{pid}/pending/accept", method = RequestMethod.GET)
	public String acceptProjectRequest(@PathVariable Long pid,
			@RequestParam(value = "uid", required = true) Long uid) {
		logger.debug("acceptProjectRequest " + pid + " " + uid);
		
		User currentUser = this.userService.getCurrentUser();
		User contributor = this.userService.findUser(uid);
		Project project = this.projectService.findProject(pid);
		
		if (project != null) {
			if (project.getMid() != currentUser.getId()) {
				return "redirect:/error/403.jsp";
			}
		} else {
			return "redirect:/error/400.jsp";
		}
		
		if (contributor == null) {
			return "redirect:/error/400.jsp";
		}
		
		this.projectService.addProjectContributor(pid, uid);
		return "redirect:/myproject/" + pid + "/pending";
	}
	
	/**
	 * Reject private project contribute request
	 * 
	 * @param pid
	 * @return
	 */
	@RequestMapping(value = "/{pid}/pending/reject", method = RequestMethod.GET)
	public String rejectProjectRequest(@PathVariable Long pid,
			@RequestParam(value = "uid", required = true) Long uid) {
		logger.debug("rejectProjectRequest " + pid + " " + uid);
		
		User currentUser = this.userService.getCurrentUser();
		User contributor = this.userService.findUser(uid);
		Project project = this.projectService.findProject(pid);
		
		if (project != null) {
			if (project.getMid() != currentUser.getId()) {
				return "redirect:/error/403.jsp";
			}
		} else {
			return "redirect:/error/400.jsp";
		}
		
		if (contributor == null) {
			return "redirect:/error/400.jsp";
		}
		
		this.projectService.removeProjectContributor(pid, uid);
		return "redirect:/myproject/" + pid + "/pending";
	}

	@RequestMapping(value = "/{pid}/control", method = RequestMethod.GET)
	public String processDeleteProject(@PathVariable Long pid,
			@RequestParam(value = "action", required = true) String action) throws Exception {

		logger.debug("delete project with id " + pid);

		if (action.equals("delete")) {
			User currentUser = this.userService.getCurrentUser();
			Project project = this.projectService.findProject(pid);
			if (project != null) {
				if (project.getMid() == currentUser.getId()) {
					projectService.deleteProject(pid);
				} else {
					return "redirect:/error/403.jsp";
				}
			} else {
				return "redirect:/error/400.jsp";
			}
		}

		return "redirect:/myproject";
	}

	@RequestMapping(value = "/{pid}/{uid}", method = RequestMethod.GET)
	public String displayContributorResources(@PathVariable("pid") Long pid,
			@PathVariable("uid") Long uid, Model model) {
		logger.debug("view contributor " + uid + " project resource with id "
				+ pid);

		User currentUser = this.userService.getCurrentUser();
		User contributor = this.userService.findUser(uid);
		Project project = this.projectService.findProject(pid);
		
		
		if (project != null) {
			if (project.getMid() != currentUser.getId()) {
				return "redirect:/error/403.jsp";
			}
		} else {
			return "redirect:/error/400.jsp";
		}
		
		if (contributor == null) {
			return "redirect:/error/400.jsp";
		}
		
		List<Resource> resourceList = resourceService.findProjectResourcesByUserId(uid, pid);
		List<Resource> currentResource = new ArrayList<Resource>();
		if (resourceList != null) {
			for (Resource r : resourceList) {
				logger.debug("getFid" + r.getFid());
				if (r.getFid() <= 0) {
					currentResource.add(r);
				}
			}
		}
		
		model.addAttribute("user", currentUser);
		model.addAttribute("contributor", contributor);
		model.addAttribute("project", project);
		model.addAttribute("resources", currentResource);
		model.addAttribute("folders", resourceService.findSubfoldersByPid(pid));

		return "contributorResource";
	}
	
	@RequestMapping(value = "/{pid}/{fid}/{uid}", method = RequestMethod.GET)
	public String displayContributorResourcesInFolder(@PathVariable("pid") Long pid,
			@PathVariable("fid") Long fid,
			@PathVariable("uid") Long uid, Model model) {
		logger.debug("view contributor " + uid + " project resource with id "
				+ pid);

		User currentUser = this.userService.getCurrentUser();
		User contributor = this.userService.findUser(uid);
		Project project = this.projectService.findProject(pid);
		
		
		if (project != null) {
			if (project.getMid() != currentUser.getId()) {
				return "redirect:/error/403.jsp";
			}
		} else {
			return "redirect:/error/400.jsp";
		}
		
		if (contributor == null) {
			return "redirect:/error/400.jsp";
		}
		
		Folder folder = resourceService.findFolder(fid);
		if (folder == null) {
			return "redirect:/error/400.jsp";
		}
		
		List<Resource> resourceList = resourceService.findProjectResourcesByUserId(uid, pid);
		List<Resource> currentResource = new ArrayList<Resource>();
		if (resourceList != null) {
			for (Resource r : resourceList) {
				logger.debug("getFid" + r.getFid());
				if (r.getFid() == fid) {
					currentResource.add(r);
				}
			}
		}
		
		List<Folder> traceFolders = resourceService.findPreFoldersById(fid);	
		
		model.addAttribute("user", currentUser);
		model.addAttribute("contributor", contributor);
		model.addAttribute("project", project);
		model.addAttribute("folder", folder);
		model.addAttribute("resources", currentResource);
		model.addAttribute("folders", resourceService.findSubfolders(fid));
		model.addAttribute("traceFolders", traceFolders);
		
		return "contributorResource";
	}

	@RequestMapping(value = "/{pid}/delete", method = RequestMethod.GET)
	public String processDeleteContributor(@PathVariable("pid") Long pid,
			@RequestParam(value = "contributor", required = true) Long uid) {

		logger.debug("delete contributor for project resource with id " + pid);
		
		
		User currentUser = this.userService.getCurrentUser();
		User contributor = this.userService.findUser(uid);
		Project project = this.projectService.findProject(pid);
		
		if (project != null) {
			if (project.getMid() != currentUser.getId()) {
				return "redirect:/error/403.jsp";
			}
		} else {
			return "redirect:/error/400.jsp";
		}
		
		if (contributor == null) {
			return "redirect:/error/400.jsp";
		}
		
		this.projectService.removeProjectContributor(pid, uid);
		return "redirect:/myproject/" + pid;
	}

	@RequestMapping(value = "/{pid}/{uid}/download", method = RequestMethod.GET)
	public void processContributorResourcesRequest(
			@PathVariable("pid") Long pid, @PathVariable("uid") Long uid,
			@RequestParam(value = "rid", required = true) Long rid,
			HttpServletResponse response) throws IOException {
		
		Project project = projectService.findProject(pid);
		if (project == null) {
			response.setStatus(400);
			return;
		}
		
		String status = projectService.getProjectStatus(userService.getCurrentUser().getId(), project);
		if (!status.equals("")) {
			if (!status.equals("granted")) {
				response.setStatus(403);
				return;
			}
		} else {
			if (project.getMid() != userService.getCurrentUser().getId()) {
				response.setStatus(403);
				return;
			}
		}
		
		Resource resource = this.resourceService.findResource(rid);
		if (resource == null) {
			response.setStatus(400);
			return;
		}
		
		if (resource.getPid() != pid) {
			response.setStatus(404);
			return;
		}
		
		response.setContentType(resource.getType());
		response.setContentLength(resource.getFile().length);
		response.setHeader("Content-Disposition", "attachment; filename=\""
				+ resource.getName() + "\"");
		FileCopyUtils.copy(resource.getFile(), response.getOutputStream());
	}

	@RequestMapping(value = "/{pid}/{uid}/delete", method = RequestMethod.GET)
	public String processContributorResourcesDelete(
			@PathVariable("pid") Long pid, @PathVariable("uid") Long uid,
			@RequestParam(value = "rid", required = true) Long rid) {
		
		User currentUser = this.userService.getCurrentUser();
		User contributor = this.userService.findUser(uid);
		Resource resource = this.resourceService.findResource(rid);
		Project project = this.projectService.findProject(pid);
		
		logger.debug("delete");
		
		if (project != null && resource != null) {
			if (project.getMid() != currentUser.getId() || resource.getPid() != project.getId()) {
				return "redirect:/error/403.jsp";
			}
		} else {
			return "redirect:/error/400.jsp";
		}
		
		if (contributor == null) {
			return "redirect:/error/400.jsp";
		}
		
		this.resourceService.removeResource(resource);
		
		return "redirect:/myproject/" + pid + "/" + uid;
	}
	
	@RequestMapping(value = "/{pid}/{fid}/{uid}/delete", method = RequestMethod.GET)
	public String processContributorFolderResourcesDelete(
			@PathVariable("pid") Long pid, @PathVariable("fid") Long fid,
			@PathVariable("uid") Long uid,
			@RequestParam(value = "rid", required = true) Long rid) {
		
		User currentUser = this.userService.getCurrentUser();
		User contributor = this.userService.findUser(uid);
		Resource resource = this.resourceService.findResource(rid);
		Project project = this.projectService.findProject(pid);
		
		logger.debug("delete with fid " + fid);
		
		if (project != null && resource != null) {
			if (project.getMid() != currentUser.getId() || resource.getPid() != project.getId()) {
				return "redirect:/error/403.jsp";
			}
		} else {
			logger.debug("error 1: " + project + " " + resource);
			
			return "redirect:/error/400.jsp";
			
		}
		
		Folder folder = resourceService.findFolder(fid);
		if (folder == null) {
			return "redirect:/error/400.jsp";
		}
		
		if (contributor == null) {
			logger.debug("error 2: " + contributor );
			
			return "redirect:/error/400.jsp";
		}
		
		this.resourceService.removeResource(resource);
		
		return "redirect:/myproject/" + pid + "/" + fid + "/" + uid;
	}
}
